"""
@author: 江同学呀
@file:  index_api.py
@date: 2025/3/13 0:00
@desc: 
    https://www.elastic.co/guide/en/elasticsearch/reference/7.17/docs-index_.html
"""
from typing import Union, Type, Optional, Dict, List, Iterable, Literal

from elastic_transport import ObjectApiResponse
from elasticsearch import Elasticsearch

from espc.common.common import Number
from espc.core.core import core
from espc.err import ESPCInvalidValueRangeError
from espc.orm.api.base_api import BaseApi
from espc.orm.model.base.base import _Base
from espc.orm.model.mapping.field.base_field.base_field import _BaseField
from espc.orm.model.model.base_document import BaseDocument
from espc.orm.model.model.base_index import BaseIndex


class IndexApi(BaseApi):
    """
    插入
    """

    def __init__(self, index: Union[Type[BaseIndex], str], *args, **kwargs):
        # todo
        super().__init__(*args, **kwargs)
        # if index not in ESPrivyCouncil._core._index_dict:
        #     raise ESPCIndexUninitError(f"未初始化{index}")
        self._index: Union[str, Type[BaseIndex]] = index
        self._document: Union[Dict, BaseDocument, None] = None
        return

    def document(self, document: Union[Dict, BaseDocument]) -> "IndexApi":
        """

        :param document:
        :return:
        """
        if self._document is not None:
            raise ValueError("文档已设置")
        self._document: Union[Dict, BaseDocument] = document
        return self

    def post(
            self, human: bool = None, filter_path: Union[str, Iterable[str]] = None,
            # flat_settings: bool = None,
            error_trace: bool = None, if_seq_no: int = None, if_primary_term: int = None,
            op_type: Literal["index", "create"] = None, pipeline: str = None,
            refresh: Literal["true", "false", "wait_for"] = None, routing: str = None, timeout: str = None,
            version: int = None, version_type: Literal["external", "external_gte"] = None,
            wait_for_active_shards: str = None, require_alias: bool = None, *args, **kwargs
    ) -> Dict[str, Union[str, List, Dict, Number]]:
        """
        POST请求
        :param human:
            Statistics are returned in a format suitable for humans (e.g. "exists_time": "1h" or "size": "1kb") and for
            computers (e.g. "exists_time_in_millis": 3600000 or "size_in_bytes": 1024). The human readable values can be
            turned off by adding ?human=false to the query string. This makes sense when the stats results are being
            consumed by a monitoring tool, rather than intended for human consumption. The default for the human flag is
            false.
            统计数据以适合人类的格式返回（例如“exists_time”： “1h”或“size”： “1kb”）和计算机（例如“exists_time_in_millis”： 3600000
            或 “size_in_bytes”： 1024）。可以通过将 ？human=false 添加到查询字符串来关闭人类可读值。当统计结果由监控工具使用而不是供人类
            使用时，这是有意义的。人为标志的默认值为 false。
        :param filter_path:
            All REST APIs accept a filter_path parameter that can be used to reduce the response returned by
            Elasticsearch. This parameter takes a comma separated list of filters expressed with the dot notation.
            所有 REST API 都接受 filter_path 参数，该参数可用于减少 Elasticsearch 返回的响应。此参数采用逗号分隔的过滤器列表，以点表示
            法表示
        # :param flat_settings:
        #     The flat_settings flag affects rendering of the lists of settings. When the flat_settings flag is true,
        #     settings are returned in a flat format.
        #     flat_settings 标志会影响设置列表的呈现。当 flat_settings 标志为 true 时，设置以平面格式返回
        :param error_trace:
            By default when a request returns an error Elasticsearch doesn’t include the stack trace of the error. You
            can enable that behavior by setting the error_trace url parameter to true.
            默认情况下，当请求返回错误时，Elasticsearch 不包含错误的堆栈跟踪。您可以通过将 error_trace url 参数设置为 true 来启用该行为。
        :param if_seq_no:
            (Optional, integer) Only perform the operation if the document has this sequence number. See Optimistic
            concurrency control.
            （可选，整数）仅当文档具有此序列号时才执行该作。请参阅乐观并发控制。
        :param if_primary_term:
            (Optional, integer) Only perform the operation if the document has this primary term. See Optimistic
            concurrency control.
            （可选，整数）仅当文档具有此主要术语时才执行该作。请参阅乐观并发控制。
        :param op_type:
            (Optional, enum) Set to create to only index the document if it does not already exist (put if absent). If
            a document with the specified _id already exists, the indexing operation will fail. Same as using the
            <index>/_create endpoint. Valid values: index, create. If document id is specified, it defaults to index.
            Otherwise, it defaults to create.
            （可选，枚举）设置为 create 以仅在文档尚不存在时为文档编制索引（如果不存在，则为 put）。如果具有指定_id的文档已存在，则索引作将
            失败。与使用 <index>/_create 端点相同。有效值：index、create。如果指定了文档 ID，则默认为 index。否则，默认为 create。
        :param pipeline:
            (Optional, string) ID of the pipeline to use to preprocess incoming documents.
            （可选，字符串）用于预处理传入文档的管道的 ID。
        :param refresh:
            (Optional, enum) If true, Elasticsearch refreshes the affected shards to make this operation visible to
            search, if wait_for then wait for a refresh to make this operation visible to search, if false do nothing
            with refreshes. Valid values: true, false, wait_for. Default: false.
            （可选，枚举）如果为 true，则 Elasticsearch 刷新受影响的分片以使此作对搜索可见，如果wait_for为 true，则等待刷新以使此作对搜
            索可见，如果为 false，则不对刷新执行任何作。有效值：true、false wait_for。默认值：false。
        :param routing:
            (Optional, string) Custom value used to route operations to a specific shard.
            （可选，字符串）用于将作路由到特定分片的自定义值。
        :param timeout:
            (Optional, time units) Period the request waits for the following operations:
                - Automatic index creation
                - Dynamic mapping updates
                - Waiting for active shards
            Defaults to 1m (one minute). This guarantees Elasticsearch waits for at least the timeout before failing.
            The actual wait time could be longer, particularly when multiple waits occur.

            （可选，时间单位）请求等待以下作的时间段：
                - 自动创建索引
                - 动态映射更新
                - 等待活动分片
            默认为 1m（1 分钟）。这保证了 Elasticsearch 在失败之前至少等待超时。实际等待时间可能会更长，尤其是在发生多个等待时。
        :param version:
            (Optional, integer) Explicit version number for concurrency control. The specified version must match the
            current version of the document for the request to succeed.
            （可选，整数）用于并发控制的显式版本号。指定的版本必须与文档的当前版本匹配，请求才能成功。
        :param version_type:
            (Optional, enum) Specific version type: external, external_gte.
            （可选，枚举）特定版本类型：external、external_gte。
        :param wait_for_active_shards:
            (Optional, string) The number of shard copies that must be active before proceeding with the operation. Set
            to all or any positive integer up to the total number of shards in the index (number_of_replicas+1).
            Default: 1, the primary shard.
            （可选，字符串）在继续执行作之前必须处于活动状态的分片副本数。设置为全部或任何正整数，最大为索引中的分片总数
            （number_of_replicas+1）。默认值：1，主分片。
        :param require_alias:
            (Optional, Boolean) If true, the destination must be an index alias. Defaults to false.
            （可选，布尔值）如果为 true，则目标必须是索引别名。默认为 false。
        :return:
        """
        if self._document is None:
            raise ESPCInvalidValueRangeError("未设置文档")
        resp: ObjectApiResponse = core.es.index(
            index=self._index if isinstance(self._index, str) else self._index._name,
            body=self._document.serialize() if isinstance(self._document, BaseDocument) else self._document,
            human=human,
            filter_path=filter_path,
            # flat_settings=flat_settings,
            error_trace=error_trace,
            if_seq_no=if_seq_no,
            if_primary_term=if_primary_term,
            op_type=op_type,
            pipeline=pipeline,
            refresh=refresh,
            routing=routing, 
            timeout=timeout,
            version=version,
            version_type=version_type,
            wait_for_active_shards=wait_for_active_shards,
            require_alias=require_alias,
            *args, **kwargs
        )
        return resp.body

    def put(self) -> Dict[str, Union[str, List, Dict, Number]]:
        raise NotImplementedError(f"还未实现 {self.__class__.__name__}.get() 方法")
